from abc import ABC, abstractmethod
from typing import Dict, Any, Optional, List, Union, Callable
import torch
from torch.utils.data import DataLoader


class EvaluationInterface(ABC):
    """Interface defining the contract for evaluation components.

    This interface ensures that any evaluation implementation provides
    consistent methods for both epoch-level and task-level evaluations.
    """

    @abstractmethod
    def evaluate_epoch(
        self,
        network: torch.nn.Module,
        data_loader: DataLoader,
        forward_fn: Callable,
        task_id: int,
        epoch_id: int,
        device: torch.device,
    ) -> Dict[str, float]:
        """Evaluate network performance for a single training epoch."""
        pass

    @abstractmethod
    def evaluate_task(
        self,
        network: torch.nn.Module,
        data_loaders: Dict[int, DataLoader],
        forward_fn: Callable,
        task_id: int,
        device: torch.device,
        *args,
        **kwargs,
    ) -> Dict[str, Any]:
        """Evaluate network performance across all completed tasks."""
        pass

    @abstractmethod
    def evaluate_current_task(
        self,
        network: torch.nn.Module,
        data_loader: DataLoader,
        forward_fn: Callable,
        task_id: int,
        device: torch.device,
    ) -> Dict[str, float]:
        """Evaluate only the current task."""
        pass

    @abstractmethod
    def get_metrics(self) -> Dict[str, List[float]]:
        """Get all tracked task-level metrics."""
        pass

    @abstractmethod
    def get_epoch_metrics(self, task_id: Optional[int] = None) -> Dict:
        """Get epoch-level metrics, optionally filtering by task."""
        pass

    @abstractmethod
    def get_best_accuracy(
        self, task_id: Optional[int] = None
    ) -> Union[Dict[int, float], float]:
        """Get best accuracy achieved."""
        pass
